﻿#ifndef CharConvert_h__2013_7_31__17_02
#define CharConvert_h__2013_7_31__17_02

#include "df.h"

namespace df
{
	namespace code{
		using namespace sdf;

		inline void WideToAnsi(const df::CCw & fromStr, std::string & toStr)
		{
#ifdef WIN32
			if (fromStr.length_ == 0)
				return;

			//gbk一般是2个字节要乘2
			auto oldSize = toStr.length();
			toStr.resize(oldSize + fromStr.length_ * 2 + 1);

			int len = WideCharToMultiByte(CP_ACP, 0, fromStr.char_, fromStr.length_, &toStr[oldSize], toStr.capacity() - oldSize, NULL, NULL);
			if (len == 0)
			{
				DF_BREAK_POINT_MSG("WideToAnsi faild");
				return;
			}
			toStr.resize(oldSize + len);
#else

#endif
		}

		//ansi一般为gbk编码
		inline void AnsiToWide(const df::CCa & fromStr, std::wstring & toStr)
		{
#ifdef WIN32
			if (fromStr.length_ == 0)
				return;

			//gbk最多2字节和unicode一样
			auto oldSize = toStr.length();
			toStr.resize(oldSize + fromStr.length_ + 1);

			//返回的长度不包括\0
			int len = MultiByteToWideChar(CP_ACP, 0, fromStr.char_, fromStr.length_, &toStr[oldSize], toStr.capacity() - oldSize);
			if (len == 0)
			{
				DF_BREAK_POINT_MSG("AnsiToWide faild");
				return;
			}
			toStr.resize(oldSize + len);
#else

#endif
		}


		FORCEINLINE int ucs4_to_utf8(uint32_t unic, uint8_t *pOutput)
		{
			DF_ASSERT(pOutput != NULL);

			if (unic < 0x00000080)
			{
				// * U-00000000 - U-0000007F:  0xxxxxxx  
				*pOutput = (uint8_t)unic;
				return 1;
			}
			else if (unic < 0x00000800)
			{
				// * U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  
				*(pOutput + 1) = (unic & 0x3F) | 0x80;
				*pOutput = ((unic >> 6) & 0x1F) | 0xC0;
				return 2;
			}
			else if (unic < 0x00010000)
			{
				// * U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx  
				*(pOutput + 2) = (unic & 0x3F) | 0x80;
				*(pOutput + 1) = ((unic >> 6) & 0x3F) | 0x80;
				*pOutput = ((unic >> 12) & 0x0F) | 0xE0;
				return 3;
			}
			else if (unic <= 0x10FFFF)
			{
				// * U-00010000 - U-0010 FFFF:  11110xxx 10xxxxxx 10xxxxxx 10xxxxxx  
				*(pOutput + 3) = (unic & 0x3F) | 0x80;
				*(pOutput + 2) = ((unic >> 6) & 0x3F) | 0x80;
				*(pOutput + 1) = ((unic >> 12) & 0x3F) | 0x80;
				*pOutput = ((unic >> 18) & 0x07) | 0xF0;
				return 4;
			}
			else if (unic <= 0x03FFFFFF)
			{
				// * U-00200000 - U-03FF FFFF:  111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
				*(pOutput + 4) = (unic & 0x3F) | 0x80;
				*(pOutput + 3) = ((unic >> 6) & 0x3F) | 0x80;
				*(pOutput + 2) = ((unic >> 12) & 0x3F) | 0x80;
				*(pOutput + 1) = ((unic >> 18) & 0x3F) | 0x80;
				*pOutput = ((unic >> 24) & 0x03) | 0xF8;
				return 5;
			}
			else if (unic <= 0x7FFFFFFF)
			{
				// * U-04000000 - U-7FFFFFFF:  1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx  
				*(pOutput + 5) = (unic & 0x3F) | 0x80;
				*(pOutput + 4) = ((unic >> 6) & 0x3F) | 0x80;
				*(pOutput + 3) = ((unic >> 12) & 0x3F) | 0x80;
				*(pOutput + 2) = ((unic >> 18) & 0x3F) | 0x80;
				*(pOutput + 1) = ((unic >> 24) & 0x3F) | 0x80;
				*pOutput = ((unic >> 30) & 0x01) | 0xFC;
				return 6;
			}

			return 0;
		}

		FORCEINLINE int ucs2_to_utf8(uint16_t unic, uint8_t *pOutput)
		{
			DF_ASSERT(pOutput != NULL);

			if (unic < 0x80)
			{
				// * U-00000000 - U-0000007F:  0xxxxxxx  
				*pOutput = (uint8_t)unic;
				return 1;
			}
			else if (unic < 0x800)
			{
				// * U-00000080 - U-000007FF:  110xxxxx 10xxxxxx  
				pOutput[1] = (unic & 0x3F) | 0x80;
				pOutput[0] = ((unic >> 6) & 0x1F) | 0xC0;
				return 2;
			}
			else
			{
				// * U-00000800 - U-0000FFFF:  1110xxxx 10xxxxxx 10xxxxxx  
				pOutput[2] = (unic & 0x3F) | 0x80;
				pOutput[1] = ((unic >> 6) & 0x3F) | 0x80;
				pOutput[0] = ((unic >> 12) & 0x0F) | 0xE0;
				return 3;
			}
		}






		inline uint32_t UTF8ToUCS4(const uint8_t * u8, intptr_t len, intptr_t & i)
		{
			uint32_t c = u8[i];
			uint32_t value = 0;
			if (c < 0x80)
			{
				i += 1;
				value = c;
			}
			else if (c < 0xC0)
			{
				i += 1;
			}
			else if (c < 0xE0 && i + 1 < len)
			{
				value = ((c & 0x1F) << 6) + (u8[i + 1] & 0x3F);
				i += 2;
			}
			else if (c < 0xF0 && i + 2 < len)
			{
				value = ((c & 0xF) << 12)
					+ (((uint32_t)u8[i + 1] & 0x3F) << 6)
					+ ((uint32_t)u8[i + 2] & 0x3F);
				i += 3;
			}
			else if (c < 0xF8 && i + 3 < len)
			{
				// 				value = ((c & 0x7) << 6) + ((uint32_t)u8[i + 1] & 0x3F);
				// 				value = (value << 6) + ((uint32_t)u8[i + 2] & 0x3F);
				// 				value = (value << 6) + ((uint32_t)u8[i + 3] & 0x3F);

				value = ((c & 0x7) << 18)
					+ (((uint32_t)u8[i + 1] & 0x3F) << 12)
					+ (((uint32_t)u8[i + 2] & 0x3F) << 6)
					+ ((uint32_t)u8[i + 3] & 0x3F);
				i += 4;
			}
			else if (c < 0xFC && i + 4 < len)
			{
				// 				value = ((c & 0x3) << 6) + ((uint32_t)u8[i + 1] & 0x3F);
				// 				value = (value << 6) + ((uint32_t)u8[i + 2] & 0x3F);
				// 				value = (value << 6) + ((uint32_t)u8[i + 3] & 0x3F);
				// 				value = (value << 6) + ((uint32_t)u8[i + 4] & 0x3F);
				value = ((c & 0x3) << 24)
					+ (((uint32_t)u8[i + 1] & 0x3F) << 18)
					+ (((uint32_t)u8[i + 2] & 0x3F) << 12)
					+ (((uint32_t)u8[i + 3] & 0x3F) << 6)
					+ ((uint32_t)u8[i + 4] & 0x3F);
				i += 5;
			}
			else if (c < 0xFC && i + 5 < len)
			{
				value = ((c & 0x1) << 6) + ((uint32_t)u8[i + 1] & 0x3F);
				value = (value << 6) + ((uint8_t)u8[i + 2] & 0x3F);
				value = (value << 6) + ((uint8_t)u8[i + 3] & 0x3F);
				value = (value << 6) + ((uint8_t)u8[i + 4] & 0x3F);
				value = (value << 6) + ((uint8_t)u8[i + 5] & 0x3F);
				i += 6;
			}
			else
				i += 1;

			return value;
		}

		inline bool UCS4IsBMP(uint32_t value)
		{
			return value < 0x10000;
		}

		inline void UCS4ToUTF16pair(uint32_t value, uint16_t & lead, uint16_t & trail)
		{
			value -= 0x10000;
			lead = (uint16_t)(0xD800 | ((value & 0xffc00) >> 10));
			trail = (uint16_t)(0xDC00 | (value & 0x003ff));
		}

		inline void UTF8ToUTF16(const df::CCa & fromStr, std::wstring & toStr)
		{
			if (fromStr.length_ == 0)
				return;

			//UTF8编码一般比unicode长
			auto oldSize = toStr.length();
			toStr.resize(oldSize + fromStr.length_ + 1);

			for (intptr_t i = 0; i < fromStr.length();)
			{
				uint32_t value = UTF8ToUCS4((uint8_t *)fromStr.char_, fromStr.length(), i);
				if (value == 0)
					continue;
				else if (UCS4IsBMP(value))
				{
					toStr[oldSize] = (wchar_t)value;
					oldSize += 1;
				}
				else
				{
					UCS4ToUTF16pair(value, (uint16_t &)toStr[oldSize], (uint16_t &)toStr[oldSize + 1]);
					oldSize += 2;
				}

			}

			toStr.resize(oldSize);
		}




		//将UTF-16辅助平面代理对(0xD800-0xDBFF,0xDC00-0xDFFF),转换为ucs4（码位范围U+10000-U+10FFFF）
		inline uint32_t UTF16ToUCS4(uint16_t lead, uint16_t trail)
		{
			return (uint32_t)0x10000 + ((uint32_t)lead - (uint32_t)0xD800) * (uint32_t)0x400 + (uint32_t)trail - (uint32_t)0xDC00;
		}

		//是否是UTF-16辅助平面代理对surrogate pair
		inline bool IsUTF16Pair(uint16_t lead)
		{
			return lead >= 0xD800 && lead <= 0xDBFF;
		}

		inline void UTF16ToUTF8(const df::CCw & fromStr, std::string & toStr)
		{

			if (fromStr.length_ == 0)
				return;

			//utf8最多6个字节(汉字3-4字节以内,4字节以上utf8需要两个wchar_t),这里取平均值乘3
			auto oldSize = toStr.length();
			toStr.resize(oldSize + fromStr.length_ * 3 + 1);

			for (intptr_t i = 0; i < fromStr.length(); i++)
			{
				uint16_t c = (uint16_t)fromStr[i];
				//4字节utf16
				if (IsUTF16Pair(c) && i + 1 < fromStr.length())
				{
					i++;
					oldSize += ucs4_to_utf8(UTF16ToUCS4(c, fromStr[i]), (uint8_t*)&toStr[oldSize]);
				}
				//2字节utf16
				else
				{
					oldSize += ucs2_to_utf8(c, (uint8_t*)&toStr[oldSize]);
				}
			}


			toStr.resize(oldSize);
		}

		inline void UTF8ToWide(const df::CCa & fromStr, std::wstring & toStr)
		{
#ifdef WIN32
			if (fromStr.length_ == 0)
				return;

			//UTF8编码一般比unicode长
			auto oldSize = toStr.length();
			toStr.resize(oldSize + fromStr.length_ + 1);

			int len = MultiByteToWideChar(CP_UTF8, 0, fromStr.char_, fromStr.length_, &toStr[oldSize], toStr.capacity() - oldSize);
			if (len == 0)
			{
				DF_BREAK_POINT_MSG("UTF8ToWide faild");
				return;
			}
			toStr.resize(oldSize + len);
#else
			UTF8ToUTF16(fromStr, toStr);
#endif
		}


		inline void WideToUTF8(const df::CCw & fromStr, std::string & toStr)
		{
#if WIN32
			if (fromStr.length_ == 0)
				return;

			//utf8最多6个字节(汉字3-4字节以内,4字节以上utf8需要两个wchar_t),这里取平均值乘3
			auto oldSize = toStr.length();
			toStr.resize(oldSize + fromStr.length_ * 3 + 1);

			int len = WideCharToMultiByte(CP_UTF8, 0, fromStr.char_, fromStr.length_, &toStr[oldSize], toStr.capacity() - oldSize, NULL, NULL);

			if (len == 0)
			{
				DF_BREAK_POINT_MSG("WideToUTF8 faild");
				return;
			}
			toStr.resize(oldSize + len);
#else
			UTF16ToUTF8(fromStr, toStr);
#endif
		}

		inline std::wstring AnsiToWide(const df::CCa & str)
		{
			std::wstring s;
			AnsiToWide(str, s);
			return s;
		}

		inline std::wstring UTF8ToWide(const df::CCa & str)
		{
			std::wstring s;
			UTF8ToWide(str, s);
			return s;
		}

		inline std::string WideToUTF8(const df::CCw & str)
		{
			std::string s;
			WideToUTF8(str, s);
			return s;
		}

		inline std::string WideToAnsi(const df::CCw & str)
		{
			std::string s;
			WideToAnsi(str, s);
			return s;
		}

		inline String CharConvert(df::CCa str)
		{
#ifdef UNICODE
			return AnsiToWide(str);
#else
			return String(str.c_str(), str.length());
#endif
		}

		inline String CharConvert(df::CCw str)
		{
#ifdef UNICODE
			return String(str.c_str(), str.length());
#else
			return WideToAnsi(str);
#endif
		}

	}

	namespace sdf{

		inline std::basic_string<wchar_t> & operator +=(std::basic_string<wchar_t> & str, const CCa & cc)
		{
#if WIN32
			code::AnsiToWide(cc, str);
#else
			code::UTF8ToUTF16(cc, str);
#endif
			return str;
		}

		inline std::basic_string<char> & operator +=(std::basic_string<char> & str, const CCw & cc)
		{
#if WIN32
			code::WideToAnsi(cc, str);
#else
			code::UTF16ToUTF8(cc, str);
#endif
			return str;
		}

		inline std::basic_string<wchar_t> & operator <<(std::basic_string<wchar_t> & str, const CCa & cc)
		{
			return str += cc;
		}

		inline std::basic_string<char> & operator <<(std::basic_string<char> & str, const CCw & cc)
		{
			return str += cc;
		}

		inline std::basic_string<wchar_t> & operator <<(std::basic_string<wchar_t> & str, const char * cc)
		{
			return str += CCa(cc);
		}

		inline std::basic_string<char> & operator <<(std::basic_string<char> & str, const wchar_t * cc)
		{
			return str += CCw(cc);
		}

		inline std::basic_string<wchar_t> && operator <<(std::basic_string<wchar_t> && str, const CCa & cc)
		{
			return std::move(str += cc);
		}

		inline std::basic_string<char> && operator <<(std::basic_string<char> && str, const CCw & cc)
		{
			return std::move(str += cc);
		}

		inline std::basic_string<wchar_t> && operator <<(std::basic_string<wchar_t> && str, const char * cc)
		{
			return std::move(str += CCa(cc));
		}

		inline std::basic_string<char> && operator <<(std::basic_string<char> && str, const wchar_t * cc)
		{
			return std::move(str += CCw(cc));
		}
	}
}

#endif // CharConvert_h__2013_7_31__17_02
